#include "STC8H.H"

// COM0_DC_L LED显示状态
#define LED_STATUS COM0_DC_L

// COM1_DC_L 电流十位
#define I_10 COM1_DC_L
// COM2_DC_L 电压十位
#define V_10 COM2_DC_L
// COM3_DC_L 电流个位
#define I_1 COM3_DC_L
// COM4_DC_L 电压个位
#define V_1 COM4_DC_L

// 电流adc为adc3
#define ADC_I 0x03
// 电压adc为adc7
#define ADC_V 0x07

typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;

__code u8 PATTERN[] =
	{
		//         0  1  2  3  4  5  6  7  8  9  E
		// seg7 dp  0  0  0  0  0  0  0  0  0  0  0
		// seg6 g   0  0  1  1  1  1  1  0  1  1  1
		// seg5 a   1  0  1  1  0  1  1  1  1  1  1
		// seg4 b   1  1  1  1  1  0  0  1  1  1  0

		// seg3 c   1  1  0  1  1  1  1  1  1  1  0
		// seg2 d   1  0  1  1  0  1  1  0  1  1  1
		// seg1 e   1  0  1  0  0  0  1  0  1  0  1
		// seg0 f   1  0  0  0  1  1  1  0  1  1  1

		0x3f, // 0 abcdef
		0x18, // 1 bc
		0x76, // 2 abged
		0x7c, // 3 abgcd
		0x59, // 4 fgbc
		0x6d, // 5 afgcd
		0x6f, // 6 afgcde
		0x38, // 7 abc
		0x7f, // 8 abcdefg
		0x7d, // 9 abcdfg

		0x80, // dp
		0x67, // e afged
};
#define sign_dp PATTERN[10]
#define char_e PATTERN[11]

#define num_0 PATTERN[0]
#define num_1 PATTERN[1]
#define num_2 PATTERN[2]
#define num_3 PATTERN[3]
#define num_4 PATTERN[4]
#define num_5 PATTERN[5]
#define num_6 PATTERN[6]
#define num_7 PATTERN[7]
#define num_8 PATTERN[8]
#define num_9 PATTERN[9]

u8 ms20_count = 0;

void Delay1000ms(void) //@12.000MHz
{
	unsigned char i, j, k;

	i = 61;
	j = 225;
	k = 62;
	do
	{
		do
		{
			while (--k)
				;
		} while (--j);
	} while (--i);
}

void Timer0_Isr(void) __interrupt(1)
{
	ms20_count++;
}

void Timer0_Init(void) // 20毫秒@12.000MHz
{
	AUXR &= 0x7F; // 定时器时钟12T模式
	TMOD &= 0xF0; // 设置定时器模式
	TL0 = 0xE0;	  // 设置定时初始值
	TH0 = 0xB1;	  // 设置定时初始值
	TF0 = 0;	  // 清除TF0标志
	TR0 = 1;	  // 定时器0开始计时
	ET0 = 1;	  // 使能定时器0中断
}

void print_i(u8 num)
{
	// 超过6.4安培错误
	if (num > 64)
	{
		I_1 = char_e;
		I_10 = char_e;
	}
	else
	{
		I_1 = PATTERN[num % 10];			// 个位
		I_10 = PATTERN[num / 10] | sign_dp; // 十位
	}
}

void print_v(u8 num)
{
	// 超过6.4安培错误
	if (num > 64)
	{
		V_1 = char_e;
		V_10 = char_e;
	}
	else if (num > 9)
	{
		V_1 = PATTERN[num % 10];		 // 个位
		V_10 = PATTERN[(num / 10) % 10]; // 十位
	}
	else
	{
		V_1 = PATTERN[num]; // 个位
		V_10 = 0x00;		// 十位消隐
	}
}

#define STATUS_SDB 0x00
#define STATUS_TES 0x01
#define STATUS_CHR 0x02
#define STATUS_FUL 0x04
#define STATUS_ERR 0x08

#define LED_SDB 0x10
#define LED_TES 0x40
#define LED_CHR 0x20
#define LED_FUL 0x80
#define LED_ERR 0x01

#define MOS_SW P16

void change_stu_2_sdb(u8 *status)
{
	// 关mos管
	MOS_SW = 0;
	// 改状态灯
	LED_STATUS = LED_SDB;
	// 改状态变量
	*status = STATUS_SDB;
}
void change_stu_2_tes(u8 *status)
{
	// 开mos管
	MOS_SW = 1;
	// 改状态灯
	LED_STATUS = LED_TES;
	// 改状态变量
	*status = STATUS_TES;
}

void change_stu_2_chr(u8 *status)
{
	// 开mos管
	MOS_SW = 1;
	// 改状态灯
	LED_STATUS = LED_CHR;
	// 改状态变量
	*status = STATUS_CHR;
}

void change_stu_2_ful(u8 *status)
{
	// 关mos管
	MOS_SW = 0;
	// 改状态灯
	LED_STATUS = LED_FUL;
	// 改状态变量
	*status = STATUS_FUL;
}

// 故障状态
void change_stu_2_err(u8 *status)
{
	// 关mos管
	MOS_SW = 0;
	// 改状态灯
	LED_STATUS = LED_ERR;
	// 改状态变量
	*status = STATUS_ERR;
}

void main(void)
{

	// P4 的值
	u8 n = 0;
	u8 ci10 = 0;
	u8 bv = 0;

	u8 ch_status = STATUS_SDB;
	u8 count_sec = 0;

	P_SW2 |= 0x80; // 扩展寄存器(XFR)访问使能

	P1M0 = 0x77; // 设置P1.3 P1.7为ADC口,其它为推挽输出。
	P1M1 = 0x88;

	P1 = 0x00; // P1 全部为低电平

	COMEN = 0x1f;  // 使能 COM0~COM7
	SEGENL = 0xff; // 使能 SEG0~SEG5

	LEDCTRL = 0x00; // LED 驱动共阴模式
	// LEDCTRL = 0x10; //LED 驱动共阳模式

	LEDCKS = 20; // 设置 LED 刷新频率

	LEDCTRL |= 0x80; // 启动 LED 驱动

	COM0_DC_L = 0x00;
	COM1_DC_L = 0x00;
	COM2_DC_L = 0x00;
	COM3_DC_L = 0x00;
	COM4_DC_L = 0x00;

	ADCTIM = 0x3f; // 设置ADC内部时序 111 1111
	ADCCFG = 0x0f; // 设置ADC时钟为系统时钟/2/16 1111
	// ADC_CONTR = 0x80 | 0x0f;   //使能ADC模块, 选择内部1.19v参考源
	ADC_CONTR = 0x80; // 使能ADC模块

	// 设置time0提供20ms时基
	Timer0_Init();

	EA = 1;

	LED_STATUS = 0x00;
	// 开启充电
	// P16 = 0x01;

	// 开始时切换成待命状态
	change_stu_2_sdb(&ch_status);

	while (1)
	{

		if (ms20_count <= 50)
		{
			continue;
		}
		ms20_count = 0;

		// n++;
		// print_i(n);

		///*
		ADC_CONTR = (ADC_CONTR & 0xf0) | ADC_I; // 切换电流adc
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		ADC_CONTR |= 0x40; // 启动AD转换
		_nop_();
		_nop_();
		while (!(ADC_CONTR & 0x20))
			;				// 查询ADC完成标志
		ADC_CONTR &= ~0x20; // 清完成标志
		// 运放39.116倍，adc_ref=2.5v，左对齐的高8位右移3位刚好是电流10倍
		ci10 = ADC_RES >> 3;
		print_i(ci10); // 打印电流

		ADC_CONTR = (ADC_CONTR & 0xf0) | ADC_V; // 切换电压adc
		// ADC_CONTR = (ADC_CONTR & 0xf0) | 0x0f;  //切换电压adc
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		_nop_();
		ADC_CONTR |= 0x40; // 启动AD转换
		_nop_();
		_nop_();
		while (!(ADC_CONTR & 0x20))
			;				// 查询ADC完成标志
		ADC_CONTR &= ~0x20; // 清完成标志

		bv = ADC_RES >> 3;
		print_v(bv); //

		count_sec++;
		// 刚开始时进入待命状态，待命状态下关闭mos管，显示绿灯，每隔3s进入测试状态
		// 测试状态下打开mos管，显示白1灯，查看电流和电压，电压<15V或者>22V进入故障状态，电流为0 返回待命状态。
		switch (ch_status)
		{
		case STATUS_SDB:
			// 待命状态
			// 每隔3s进入检测状态
			if (count_sec > 3)
			{
				count_sec = 0;
				change_stu_2_tes(&ch_status);
			}

			break;

		case STATUS_TES:
			// 检测状态
			if ((bv > 22) | (bv < 15))
			{
				// 进入错误状态
				count_sec = 0;
				change_stu_2_err(&ch_status);
			}
			else
			{
				// 如果3s过去后，ci10 > 2， 进入充电状态，否则进入待命状态
				if (count_sec > 3)
				{
					count_sec = 0;
					if (ci10 > 2)
					{
						change_stu_2_chr(&ch_status);
					}
					else
					{
						change_stu_2_sdb(&ch_status);
					}
				}
			}
			break;

		case STATUS_CHR:
		    //每3秒检测一次电流电压，电压不在区间进入故障状态，电流小于2时进入充满状态
			// 检测状态
			if ((bv > 22) | (bv < 15))
			{
				// 进入错误状态
				count_sec = 0;
				change_stu_2_err(&ch_status);
			}
			else
			{
				// 每3s检查电流，ci10 < 2， 进入充满状态
				if (count_sec > 3)
				{
					count_sec = 0;
					if (ci10 < 2)
					{
						change_stu_2_ful(&ch_status);
					}
				}
			}

			break;

		case STATUS_FUL:
			break;

		case STATUS_ERR:
			break;

		default:
			ch_status = STATUS_ERR;
			break;
		}
		//*/
	}
}
